/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.farmcode.plugin.objectinfo.jdbc;

import com.farmcode.api.runtime.FARMCodeContext;
import com.farmcode.api.runtime.metadata.Procedure;
import com.farmcode.api.runtime.metadata.ProcedureSpc;
import com.farmcode.api.runtime.metadata.procedure.Input;
import com.farmcode.api.runtime.metadata.procedure.Output;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author oiprado
 */
public class ProceduresDatabaseObjectInfo extends DatabaseInfo<Procedure, Procedure> {

    List<Procedure> objectInfos = new ArrayList<Procedure>();
    private int paramIndex = 0;

    public ProceduresDatabaseObjectInfo(FARMCodeContext context) throws ClassNotFoundException {
        super(context);
    }

    @Override
    public List<Procedure> explore() throws SQLException {

        Connection connection = getConnection();
        String schema = (String) context.get(FARMCodeContext.SCHEMA);
        DatabaseMetaData databaseMetaData = connection.getMetaData();
        ResultSet procedures = databaseMetaData.getProcedures(null, (schema).equals("") ? null : schema, null);
        while (procedures != null && procedures.next()) {
            String name = procedures.getString("PROCEDURE_NAME");
            if (name.contains("diagram")) {
                continue;
            }
            Procedure objectInfo = new ProcedureSpc();
            objectInfo.setName(name.split(";")[0]);
            objectInfos.add(objectInfo);

            ResultSet procedureColumns = databaseMetaData.getProcedureColumns(null, null, name.split(";")[0], null);

            while (procedureColumns != null && procedureColumns.next()) {
                String columnName = procedureColumns.getString("COLUMN_NAME");
                int column = procedureColumns.getInt("DATA_TYPE");

                if (!"@RETURN_VALUE".equals(columnName)) {
                    Input input = new Input();
                    input.setName(columnName);
//                    input.setType(column);
//                    input.setdataType getTypes().get(column).getName());
                    objectInfo.getInputChilds().add(input);
                    paramIndex++;
                }

            }
        }
        return objectInfos;
    }

    @Override
    public Procedure exploreChilds(Procedure dbo) throws SQLException {

        Connection connection = getConnection();
        String paramsProcedures = "";

        for (int index = 0; index < dbo.getInputChilds().size(); index++) {
            paramsProcedures += (index + 1) < dbo.getInputChilds().size() ? "?," : "?";
        }
        CallableStatement callableStatement = connection.prepareCall("{call " + dbo.getName() + " (" + paramsProcedures + ")}");

        for (int i = 0; i < dbo.getInputChilds().size(); i++) {
            Integer integer = new Integer(dbo.getInputChilds().get(i).getType());
            callableStatement.setObject(i + 1, convertTo(integer)[0]);
        }

        boolean executed = callableStatement.execute();
        if (!executed) {
            return dbo;
        }

        ResultSetMetaData procedureMetatada = callableStatement.getMetaData();
        int columnSize = procedureMetatada.getColumnCount();
        int index = 1;
        while (index <= columnSize) {
            Output output = new Output();
            output.setName(procedureMetatada.getColumnName(index));
//            output.put("dataType", getTypes().get(procedureMetatada.getColumnType(index)).getName());
            dbo.getOutputChilds().add(output);
            index++;
        }
        return dbo;
    }

    private Object[] convertTo(int type) {
        switch (type) {
            case Types.VARCHAR:
                return new Object[]{"", "String"};
            case Types.NUMERIC:
                return new Object[]{new Long(0), "Long"};
            case Types.INTEGER:
                return new Object[]{new Integer(0), "Integer"};
            case Types.TIME:
                return new Object[]{new Date(System.currentTimeMillis()), "Date"};
            case Types.TIMESTAMP:
                return new Object[]{new Date(System.currentTimeMillis()), "Date"};
            default:            
                return new Object[]{"0", "undefined"};
        }        
    }
}
